package com.ytjj.qmyx.admin.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.google.common.base.Joiner;
import com.ytjj.common.api.CommonPage;
import com.ytjj.common.api.CommonResult;
import com.ytjj.common.constants.RedisConstants;
import com.ytjj.common.exception.ApiException;
import com.ytjj.common.service.RedisService;
import com.ytjj.common.utils.DateTimeUtil;
import com.ytjj.common.utils.HttpClientUtil;
import com.ytjj.common.utils.OrderUtils;
import com.ytjj.qmyx.admin.config.SupplyApiConfig;
import com.ytjj.qmyx.admin.dao.EarlyReimbursementOrderDao;
import com.ytjj.qmyx.admin.dao.ReimbursementOrdersDao;
import com.ytjj.qmyx.admin.mapper.AdminMapper;
import com.ytjj.qmyx.admin.mapper.ReimbursementExcelRecordMapper;
import com.ytjj.qmyx.admin.mapper.ReimbursementOrdersInfoMapper;
import com.ytjj.qmyx.admin.mapper.ReimbursementOrdersMapper;
import com.ytjj.qmyx.admin.model.*;
import com.ytjj.qmyx.admin.model.excel.demo3.CustomImageModifyHandler;
import com.ytjj.qmyx.admin.model.excel.demo3.ReimbursementOrdersExcel;
import com.ytjj.qmyx.admin.model.excel.myDemo.ExcelData;
import com.ytjj.qmyx.admin.model.excel.myDemo.ExcelRead;
import com.ytjj.qmyx.admin.model.request.ReiOrderRequest;
import com.ytjj.qmyx.admin.model.request.ReimbursementOrderRequest;
import com.ytjj.qmyx.admin.model.response.*;
import com.ytjj.qmyx.admin.service.AdminService;
import com.ytjj.qmyx.admin.service.MemberService;
import com.ytjj.qmyx.admin.service.ReimbursementOrdersService;
import com.ytjj.qmyx.mall.mapper.OrdersInfoMapper;
import com.ytjj.qmyx.mall.model.Banker;
import com.ytjj.qmyx.mall.model.OrdersInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.util.CellRangeAddress;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.net.URL;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * @author jiawei
 * @date 2023年11月13日 10:47
 * @describe
 */
@Service
@Slf4j
public class ReimbursementOrdersServiceImpl implements ReimbursementOrdersService {

    @Autowired
    ReimbursementOrdersInfoMapper reimbursementOrdersInfoMapper;
    @Autowired
    ReimbursementOrdersMapper reimbursementOrdersMapper;
    @Autowired
    ReimbursementOrdersDao reimbursementOrdersDao;
    @Autowired
    MemberService memberService;
    @Autowired
    private AdminService adminService;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private SupplyApiConfig supplyApiConfig;
    @Resource
    private OrdersInfoMapper ordersInfoMapper;
    @Resource
    private EarlyReimbursementOrderDao earlyReimbursementOrderDao;
    @Resource
    private AdminMapper adminMapper;

    @Resource
    private ReimbursementExcelRecordMapper reimbursementExcelRecordMapper;
    @Resource
    private RedisService redisService;

    @Value(value = "${orderPath:}")
    private String orderPath;

    Executor pools = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1024 * 1024));

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer createOrUpdateReiOrder(ReiOrderRequest request) {
        Admin admin = memberService.getAdmin();
        ReimbursementOrders reimbursementOrders = new ReimbursementOrders();
        BeanUtils.copyProperties(request,reimbursementOrders);
        List<ReiOrderRequest.ReiOrderInfoResponses> relevantOrders = request.getReiOrderInfoResponses();
        String adminId = redisService.get(RedisConstants.REIMBURSEMENT_AUDIT_KEY+request.getId());
        if(StringUtils.isNotEmpty(adminId) && !admin.getId().equals(Integer.valueOf(adminId))){
            Admin opAdmin = adminService.selectAdminById(Integer.valueOf(adminId));
            throw new ApiException("当前报销单"+opAdmin.getName()+"正在操作中，无法修改！");
        }
        if(CollectionUtils.isEmpty(relevantOrders)){
            throw new ApiException("关联的子订单不能为空！");
        }
        List<String> childOrderNos = relevantOrders.stream().map(e -> e.getChildOrderNo()).collect(Collectors.toList());
        String childOrderNo = StringUtils.join(childOrderNos, ",");
        if(StringUtils.isBlank(childOrderNo)){
            throw new ApiException("关联的子订单不能为空！");
        }else {
            List<OrdersInfo> ordersInfos = ordersInfoMapper.selectByChildOrderNoList(childOrderNos);
            for (String orderNo : childOrderNos) {
                boolean b = ordersInfos.stream().noneMatch(e -> e.getChildOrderNo().equals(orderNo));
                if(b){
                    throw new ApiException(String.format("子订单:%s不存在，请核对后再提交！",orderNo));
                }
            }
        }
        if(null == request.getApplyAmount() || request.getApplyAmount().compareTo(BigDecimal.ZERO) == 0){
            throw new ApiException("费用不能为空或者0！");
        }
        Map<String, Long> childOrderNoMap = relevantOrders.stream().collect(Collectors.groupingBy(ReiOrderRequest.ReiOrderInfoResponses::getChildOrderNo, Collectors.counting()));
        for (Map.Entry<String, Long> map : childOrderNoMap.entrySet()) {
            Long value = map.getValue();
            if(value > 1){
                throw new ApiException("子订单号不能相同！");
            }
        }
        List<Menu> menuAllByTel = adminService.getMenuAllByTel(admin.getEmail());
        boolean isManager = menuAllByTel.stream().anyMatch(e -> "reimbursement:editManager".equals(e.getApiCode()));
        reimbursementOrders.setRelevantOrders(childOrderNo);
        //修改
        if(request.getId() != null){
            if(checkReimbursement(childOrderNos,request.getId())){
                throw new ApiException("操作失败,当前子订单还未报销，请勿重复提交申请！");
            }
            RLock lock = redissonClient.getLock(RedisConstants.REIMBURSEMENT_LOCK_ + request.getId());
            try {
                boolean b = lock.tryLock(0, 5, TimeUnit.SECONDS);
                if (b) {
                    ReimbursementOrders oldEntity = reimbursementOrdersMapper.selectByPrimaryKey(request.getId());
                    //非管理人员和非财务人员不能修改别人创建的报销单
                    if(!admin.getId().equals(oldEntity.getCreateUserId()) && !isManager){
                        throw new ApiException("您无法修改他人创建的报销单，请联系管理人员！");
                    }
                    if(null != oldEntity.getStatus() && oldEntity.getStatus() == 1){
                        throw new ApiException("无法修改已审核的报销单,请删除后重建");
                    }
                    if(null != oldEntity.getStatus() && oldEntity.getStatus() == 2){
                        throw new ApiException("无法修改已报销的单");
                    }
                    reimbursementOrders.setReimburser(null);
                    reimbursementOrders.setReimburserName(null);
                    reimbursementOrders.setReimbursementProof(null);
                    reimbursementOrders.setReimbursementTime(null);
                    reimbursementOrders.setFinancialRemarks(null);
                    reimbursementOrders.setUpdateTime(new Date());
                    reimbursementOrders.setUpdateUserId(admin.getId());
                    reimbursementOrders.setUpdateUserName(admin.getName());
                    ReimbursementOrdersInfoExample example = new ReimbursementOrdersInfoExample();
                    example.createCriteria().andReimbursementIdEqualTo(request.getId()).andIsDeletedEqualTo(0);
                    ReimbursementOrdersInfo delItem = new ReimbursementOrdersInfo();
                    delItem.setIsDeleted(1);
                    reimbursementOrdersInfoMapper.updateByExampleSelective(delItem, example);
                    reimbursementOrdersMapper.updateByPrimaryKeySelective(reimbursementOrders);
                    for (ReiOrderRequest.ReiOrderInfoResponses relevantOrder : relevantOrders) {
                        ReimbursementOrdersInfo reimbursementOrdersInfo = new ReimbursementOrdersInfo();
                        BeanUtils.copyProperties(relevantOrder, reimbursementOrdersInfo);
                        reimbursementOrdersInfo.setReimbursementId(request.getId());
                        reimbursementOrdersInfo.setUpdateTime(new Date());
                        reimbursementOrdersInfoMapper.insertSelective(reimbursementOrdersInfo);
                    }
                }
            } catch (Exception e) {
                log.error("操作失败,{}", e);
                throw new ApiException("操作失败！" + e.getMessage());
            }finally {
                lock.unlock();
            }
        }else { //新增
            if (checkReimbursement(childOrderNos, null)) {
                throw new ApiException("操作失败,当前子订单还未报销，请勿重复提交申请！");
            }
            reimbursementOrders.setReimburser(null);
            reimbursementOrders.setReimburserName(null);
            reimbursementOrders.setReimbursementProof(null);
            reimbursementOrders.setReimbursementTime(null);
            reimbursementOrders.setFinancialRemarks(null);
            reimbursementOrders.setReturnedAmount(null);
            reimbursementOrders.setReimbursementNo(OrderUtils.getReimbursementCode(admin.getId()));
            reimbursementOrders.setCreateTime(new Date());
            reimbursementOrders.setCreateUserId(admin.getId());
            reimbursementOrders.setCreateUser(admin.getName());
            reimbursementOrders.setStatus(0);
            reimbursementOrdersMapper.insertSelective(reimbursementOrders);
            for (ReiOrderRequest.ReiOrderInfoResponses relevantOrder : relevantOrders) {
                ReimbursementOrdersInfo reimbursementOrdersInfo = new ReimbursementOrdersInfo();
                BeanUtils.copyProperties(relevantOrder, reimbursementOrdersInfo);
                reimbursementOrdersInfo.setReimbursementId(reimbursementOrders.getId());
                reimbursementOrdersInfoMapper.insertSelective(reimbursementOrdersInfo);
            }
        }
        return 1;
    }

    @Override
    public String checkReiOrderInfo(String childOrderNos,String id) {
        StringBuilder sb = new StringBuilder();
        String[] childOrderNoArray = childOrderNos.split(",");
        //查询早期是否已报销
        for (String childOrderNo : childOrderNoArray) {
            Integer entityByParams = earlyReimbursementOrderDao.getEntityByParams(childOrderNo);
            if (null != entityByParams) {
                sb.append("子订单：" + childOrderNo + "已报销！（存在于早期云文档中）; ");
            } else { //是否在平台已报销
                List<ReiOrderQueryResponse> countExist = reimbursementOrdersDao.getCountExist(childOrderNo, StringUtils.isEmpty(id) ? null : Integer.valueOf(id));
                if (!CollectionUtils.isEmpty(countExist)) {
                    sb.append(String.format("子订单：%s,已在系统存在【%s笔】报销单！", childOrderNo, countExist.size()));
                    break;
                }
            }
        }
        if (StringUtils.isNotEmpty(sb)) {
            sb.append("是否继续操作?");
        }
        return sb.toString();
    }

    @Override
    public Integer approvalOrReimburse(ReiOrderRequest request) {
        Admin admin = memberService.getAdmin();
        ReimbursementOrders reimbursementOrders = new ReimbursementOrders();
        reimbursementOrders.setId(request.getId());
        ReimbursementOrders oldReimbursementOrder = reimbursementOrdersMapper.selectByPrimaryKey(request.getId());
        if (null != request.getReturnedAmount() && request.getReturnedAmount().compareTo(BigDecimal.ZERO) != 0
                && oldReimbursementOrder.getApplyAmount().compareTo(request.getReturnedAmount()) != 0) {
            throw new ApiException("报销金额必须和申请金额一致！");
        }
        reimbursementOrders.setApprovalUserId(admin.getId());
        reimbursementOrders.setApprovalUserName(admin.getName());
        reimbursementOrders.setApprovalTime(new Date());
        reimbursementOrders.setReimbursementTime(null);
        reimbursementOrders.setReimburser(null);
        reimbursementOrders.setReimburserName(null);
        if (StringUtils.isNotEmpty(request.getReimbursementProof())) {//报销操作
            if(request.getReturnedAmount() == null || request.getReturnedAmount().compareTo(BigDecimal.ZERO) == 0){
                throw new ApiException("已报销金额不能是0或者不能为空！");
            }
            reimbursementOrders.setStatus(2);
            reimbursementOrders.setReimburser(admin.getId());
            reimbursementOrders.setReimburserName(admin.getName());
            reimbursementOrders.setReimbursementTime(request.getReimbursementTime());
        } else if (null != request.getReturnedAmount() && request.getReturnedAmount().compareTo(BigDecimal.ZERO) > 0) {//审核操作
            if(StringUtils.isEmpty(request.getFinancialRemarks()) && null == request.getReimbursementTime()){
                reimbursementOrders.setStatus(0);
            }else {
                reimbursementOrders.setStatus(1);
            }
        }else {
            reimbursementOrders.setStatus(0);
        }
        reimbursementOrders.setReimbursementProof(StringUtils.isEmpty(request.getReimbursementProof()) ? "" : request.getReimbursementProof());
        reimbursementOrders.setReturnedAmount(request.getReturnedAmount());
        reimbursementOrders.setFinancialRemarks(request.getFinancialRemarks());
        int i = reimbursementOrdersDao.updateReimbursementOrder(reimbursementOrders);
        return i;
    }

    /**
     * 当前子订单是否存在报销中的单
     * @param reimbursementId 报销单id
     * @param childOrderNos
     * @return boolean = true 存在，false 不存在
     */
    public boolean checkReimbursement(List<String> childOrderNos,Integer reimbursementId){
        ReimbursementOrdersInfoExample example = new ReimbursementOrdersInfoExample();
        example.createCriteria().andChildOrderNoIn(childOrderNos).andIsDeletedEqualTo(0);
        //1.判断当前子订单号是否存在未报销的订单
        List<ReimbursementOrdersInfo> reimbursementOrdersInfos = reimbursementOrdersInfoMapper.selectByExample(example);
        List<Integer> ids = reimbursementOrdersInfos.stream().map(e -> e.getReimbursementId()).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(ids)){
            return false;
        }
        ReimbursementOrdersExample ordersExample = new ReimbursementOrdersExample();
        ordersExample.createCriteria().andIdIn(ids).andIsDeletedEqualTo(0);
        List<ReimbursementOrders> reimbursement = reimbursementOrdersMapper.selectByExample(ordersExample);
        boolean mark = reimbursement.stream().anyMatch(e -> null == e.getReimbursementTime() && !e.getId().equals(reimbursementId));
        return mark;
    }

    @Override
    public ReiOrderResponse getReiOrderDetail(Integer id) {
        ReiOrderResponse reiOrderResponse = new ReiOrderResponse();
        ReimbursementOrders reimbursementOrders = reimbursementOrdersMapper.selectByPrimaryKey(id);
        BeanUtils.copyProperties(reimbursementOrders,reiOrderResponse);
        List<ReiOrderInfoResponse> details = reimbursementOrdersDao.getDetailByReimbursementId(id);
        reiOrderResponse.setReiOrderInfoResponses(details);
        return reiOrderResponse;
    }

    @Override
    public CommonPage<ReiOrderQueryResponse> getReimbursementOrders(ReimbursementOrderRequest request) {
        PageHelper.startPage(request.getPageNum(),request.getPageSize());
        List<ReiOrderQueryResponse> reiOrderDetail = reimbursementOrdersDao.getReiOrderDetail(request);
        CommonPage<ReiOrderQueryResponse> restPage = CommonPage.restPage(reiOrderDetail);
        CountDownLatch countDownLatch = new CountDownLatch(reiOrderDetail.size());
        for (ReiOrderQueryResponse reiOrder : reiOrderDetail) {
            List<RelevantOrdersDetail> relevantOrdersDetailList = new ArrayList<>();
            pools.execute(() -> {
                try {
                    //报销单相关的子订单详情
                    List<ReiOrderInfoResponse> relevantOrdersDetails = reimbursementOrdersDao.getDetailByReimbursementId(reiOrder.getId());
                    List<String> childOrderNos = relevantOrdersDetails.stream().map(e -> e.getChildOrderNo()).collect(Collectors.toList());
                    //关联的订单数量信息
                    Map<String, RelevantOrdersDetail> collect = new HashMap<>();
                    if (!CollectionUtils.isEmpty(childOrderNos)) {
                        List<RelevantOrdersDetail> relevants = reimbursementOrdersDao.getCountForChildNo(childOrderNos);
                        collect = relevants.stream().collect(Collectors.toMap(e -> e.getChildOrderNo(), Function.identity()));
                    }
                    for (ReiOrderInfoResponse e : relevantOrdersDetails) {
                        RelevantOrdersDetail relevantOrdersDetail = new RelevantOrdersDetail();
                        BeanUtils.copyProperties(e, relevantOrdersDetail);
                        if (!CollectionUtils.isEmpty(collect)) {
                            RelevantOrdersDetail relevant = collect.get(e.getChildOrderNo());
                            if (null != relevant) {
                                relevantOrdersDetail.setReimbursementTimes(relevant.getReimbursementTimes());
                            }
                        }
                        relevantOrdersDetailList.add(relevantOrdersDetail);
                    }
                } catch (BeansException e) {
                    log.error("报销管理查询出错===》{}",e);
                } finally {
                    countDownLatch.countDown();
                }
            });
            reiOrder.setRelevantOrdersDetails(relevantOrdersDetailList);
        }
        try {
            countDownLatch.await();
        } catch (Exception e) {
            log.error("报销管理查询出错===》{}", e);
        }
        return restPage;
    }


    @Override
    public void exportReimbursementOrders(ReimbursementOrderRequest request){
        Admin admin = memberService.getAdmin();
        String startCreateTime = request.getStartReimbursementTime();
        String endCreateTime = request.getEndReimbursementTime();
        if((StringUtils.isEmpty(startCreateTime) || StringUtils.isEmpty(endCreateTime)) && request.getStatus()!=0){
            throw new ApiException("报销时间不能为空");
        }
        if (request.getStatus() == 0){
            startCreateTime = request.getStartCreateTime();
            endCreateTime = request.getEndCreateTime();
            if (StringUtils.isEmpty(startCreateTime) || StringUtils.isEmpty(endCreateTime)){
                throw new ApiException("提单日期不能为空");
            }
        }

        Date startDate =  DateTimeUtil.StrToTime(startCreateTime);
        Date endtDate = DateTimeUtil.StrToTime(endCreateTime);
        int day = 0;
        try {
            day = DateTimeUtil.daysBetween(startDate, endtDate);
        } catch (ParseException e) {
            throw new ApiException("时间解析出错！");
        }
        if (day > 31) {
            throw new ApiException("导出时间区间不能超过31天");
        }
        //限制频繁操作
        ReimbursementExcelRecord excelRecord = reimbursementOrdersDao.getExcelRecord(admin.getId());
        if (excelRecord != null && excelRecord.getStatus() == 0) {
            //距离上次操作的时间
            throw new ApiException("请勿频繁点击，请等待前一次导出结束！");
        }
        List<ReiOrderQueryResponse> reiOrderDetail = reimbursementOrdersDao.getReiOrderDetail(request);
        if(reiOrderDetail.size() > 5000){
            throw new ApiException("导出数量大于上限5000条，请分多次下载！");
        }
        if(reiOrderDetail.size() == 0){
            throw new ApiException("数据为空！");
        }
        //异步生成excel
        String finalStartCreateTime = startCreateTime;
        String finalEndCreateTime = endCreateTime;
        pools.execute(()->{
            // 定义批次大小
            int batchSize = 200;
            // 获取数据总数
            int totalCount = reiOrderDetail.size();
            // 计算需要分批的次数
            int batchCount = (totalCount + batchSize - 1) / batchSize;
            DateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
            String fileName = "报账订单" + sdf.format(new Date());
            String fullName = fileName + (batchCount > 1 ? ".zip" : ".xlsx");
            ReimbursementExcelRecord reimbursementExcelRecord = new ReimbursementExcelRecord();
            reimbursementExcelRecord.setCreateUserId(admin.getId());
            reimbursementExcelRecord.setCreateTime(new Date());
            reimbursementExcelRecord.setFileName(fullName);
            reimbursementExcelRecord.setStatisticalDate(finalStartCreateTime + "-" + finalEndCreateTime);
            reimbursementExcelRecord.setStatus(0);
            reimbursementExcelRecordMapper.insert(reimbursementExcelRecord);

            int resultCount = 0;
            for (int i = 0; i < batchCount; i++) {
                int startIndex = i * batchSize;
                int endIndex = Math.min(startIndex + batchSize, totalCount);
                List<ReiOrderQueryResponse> batchData = reiOrderDetail.subList(startIndex, endIndex);
                resultCount += doExportExcel(batchData, fileName + "(" + (i + 1) + ")");
            }
            if(resultCount == batchCount){
                //更新导出记录
                reimbursementExcelRecord.setFinishTime(new Date());
                reimbursementExcelRecord.setStatus(1);
                reimbursementExcelRecord.setFileSplitQuantity(batchCount);
                reimbursementExcelRecordMapper.updateByPrimaryKeySelective(reimbursementExcelRecord);
                log.info("===报销单导出成功====" + fullName);
            }else {
                reimbursementExcelRecord.setStatus(2);
                reimbursementExcelRecordMapper.updateByPrimaryKeySelective(reimbursementExcelRecord);
                log.info("===报销单导出失败====" + fullName);
            }
        });
    }

    /**
     * 生成Excel
     */
    public Integer doExportExcel(List<ReiOrderQueryResponse> reiOrderDetail,String splitName){
        FileOutputStream outputStream = null;
        try {
            CountDownLatch countDownLatch = new CountDownLatch(reiOrderDetail.size());
            for (ReiOrderQueryResponse reiOrder : reiOrderDetail) {
                List<RelevantOrdersDetail> relevantOrdersDetailList = new ArrayList<>();
                pools.execute(() -> {
                    try {
                        //报销单相关的子订单详情
                        List<ReiOrderInfoResponse> relevantOrdersDetails = reimbursementOrdersDao.getDetailByReimbursementId(reiOrder.getId());
                        List<String> childOrderNos = relevantOrdersDetails.stream().map(e -> e.getChildOrderNo()).collect(Collectors.toList());
                        //关联的订单数量信息
                        Map<String, RelevantOrdersDetail> collect = new HashMap<>();
                        if (!CollectionUtils.isEmpty(childOrderNos)) {
                            List<RelevantOrdersDetail> relevants = reimbursementOrdersDao.getCountForChildNo(childOrderNos);
                            collect = relevants.stream().collect(Collectors.toMap(e -> e.getChildOrderNo(), Function.identity()));
                        }
                        for (ReiOrderInfoResponse e : relevantOrdersDetails) {
                            RelevantOrdersDetail relevantOrdersDetail = new RelevantOrdersDetail();
                            BeanUtils.copyProperties(e, relevantOrdersDetail);
                            if (!CollectionUtils.isEmpty(collect)) {
                                RelevantOrdersDetail relevant = collect.get(e.getChildOrderNo());
                                if (null != relevant) {
                                    relevantOrdersDetail.setReimbursementTimes(relevant.getReimbursementTimes());
                                }
                            }
                            relevantOrdersDetailList.add(relevantOrdersDetail);
                        }
                    } catch (BeansException e) {
                        log.error("报销管理查询出错===》{}", e);
                    } finally {
                        countDownLatch.countDown();
                    }
                });
                reiOrder.setRelevantOrdersDetails(relevantOrdersDetailList);
            }
            try {
                countDownLatch.await();
            } catch (Exception e) {
                log.error("报销管理查询出错===》{}", e);
            }
            //排序
            List<ReiOrderQueryResponse> result = reiOrderDetail.stream().sorted(Comparator.comparing(ReiOrderQueryResponse::getId).reversed()).collect(Collectors.toList());
            //去重后商品对应的供应商id
            Set<Integer> bankerIds = new HashSet<>();
            for (ReiOrderQueryResponse reiOrderQueryResponse : result) {
                List<RelevantOrdersDetail> relevantOrdersDetails = reiOrderQueryResponse.getRelevantOrdersDetails();
                bankerIds.addAll(relevantOrdersDetails.stream().map(RelevantOrdersDetail::getBankerId).collect(Collectors.toSet()));
            }
            //获取供应链供应商信息
            List<Banker> bankerList = new ArrayList<>();
            if (!CollectionUtils.isEmpty(bankerIds)) {
                Map<String, String> param = new HashMap<>();
                param.put("bankerIds", Joiner.on(",").join(bankerIds));
                String resultJson = HttpClientUtil.doGet(supplyApiConfig.getUrl() + "/banker/queryBankerByIds", param, supplyApiConfig.getHeadsMap());
                CommonResult commonResult = JSONObject.parseObject(resultJson, CommonResult.class);
                if (200 == commonResult.getCode()) {
                    bankerList = JSONArray.parseArray(commonResult.getData().toString(), Banker.class);
                }
            }
            Map<Integer, Banker> collect = bankerList.stream().collect(Collectors.toMap(Banker::getId, Function.identity()));
            //需要合并的单元格
            List<CellRangeAddress> cellRangeAddresses = new ArrayList<>();
            //从第几行开始
            int firstColIndex = 1;
            List<ReimbursementOrdersExcel> list = new ArrayList<>();
            for (int i = 0; i < result.size(); i++) {
                ReiOrderQueryResponse reiOrderQueryResponse = result.get(i);
                List<RelevantOrdersDetail> relevantOrdersDetails = reiOrderQueryResponse.getRelevantOrdersDetails();
                for (int j = 0; j < relevantOrdersDetails.size(); j++) {
                    RelevantOrdersDetail relevantOrdersInfo = relevantOrdersDetails.get(j);
                    ReimbursementOrdersExcel reimbursementOrdersExcel = new ReimbursementOrdersExcel();
                    //设置供应商信息
                    Banker banker = collect.get(relevantOrdersInfo.getBankerId());
                    reimbursementOrdersExcel.setBankerName(null != banker ? banker.getName() : null);
                    reimbursementOrdersExcel.setCreateTime(DateTimeUtil.TimeToStr(reiOrderQueryResponse.getCreateTime()));
                    reimbursementOrdersExcel.setReimbursementNo(reiOrderQueryResponse.getReimbursementNo());
                    reimbursementOrdersExcel.setChildOrderNo(relevantOrdersInfo.getChildOrderNo());
                    reimbursementOrdersExcel.setReimbursementTimes(String.valueOf(relevantOrdersInfo.getReimbursementTimes()));
                    reimbursementOrdersExcel.setUserName(relevantOrdersInfo.getUserName());
                    reimbursementOrdersExcel.setUserPhone(relevantOrdersInfo.getUserPhone());
                    reimbursementOrdersExcel.setReason(relevantOrdersInfo.getReason());
                    reimbursementOrdersExcel.setPayer(relevantOrdersInfo.getPayer() == 1 ? "仓库承担" : relevantOrdersInfo.getPayer() == 2 ? "平台承担" : relevantOrdersInfo.getPayer() == 3 ? "客户承担" : "未知");
                    reimbursementOrdersExcel.setStatusText(reiOrderQueryResponse.getStatus() == 0 ? "待报销" : reiOrderQueryResponse.getStatus() == 1 ? "已审核" : reiOrderQueryResponse.getStatus() == 2 ? "已报销" : "未知");
                    reimbursementOrdersExcel.setApplyAmount(String.valueOf(reiOrderQueryResponse.getApplyAmount()));
                    if (j == 0) {
                        //只导出一次
                        String freightPaymentProof = reiOrderQueryResponse.getFreightPaymentProof();
                        String customerCodeImg = reiOrderQueryResponse.getCustomerCodeImg();
                        String reimbursementProof = reiOrderQueryResponse.getReimbursementProof();
                        reimbursementOrdersExcel.setFreightPaymentProof(StringUtils.isNotEmpty(freightPaymentProof) ? Arrays.asList(new URL(freightPaymentProof)) : null);
                        reimbursementOrdersExcel.setCustomerCodeImg(StringUtils.isNotEmpty(customerCodeImg) ? Arrays.asList(new URL(customerCodeImg)) : null);
                        reimbursementOrdersExcel.setReimbursementProof(StringUtils.isNotEmpty(reimbursementProof) ? Arrays.asList(new URL(reimbursementProof)) : null);

                    }
                    reimbursementOrdersExcel.setCustomerAccountInfo(reiOrderQueryResponse.getCustomerAccountInfo());
                    reimbursementOrdersExcel.setCreateUser(reiOrderQueryResponse.getCreateUser());
                    reimbursementOrdersExcel.setServiceRemarks(reiOrderQueryResponse.getServiceRemarks());
                    reimbursementOrdersExcel.setFinancialRemarks(reiOrderQueryResponse.getFinancialRemarks());
                    Date reimbursementTime = reiOrderQueryResponse.getReimbursementTime();
                    reimbursementOrdersExcel.setReimbursementTime(null == reimbursementTime ? null : DateTimeUtil.TimeToStr(reimbursementTime));
                    String returnedAmount = (reiOrderQueryResponse.getReturnedAmount() == null || reiOrderQueryResponse.getReturnedAmount().compareTo(BigDecimal.ZERO) == 0) ? "" : String.valueOf(reiOrderQueryResponse.getReturnedAmount());
                    reimbursementOrdersExcel.setReturnedAmount(returnedAmount);
                    reimbursementOrdersExcel.setReimburserName(reiOrderQueryResponse.getReimburserName());
                    list.add(reimbursementOrdersExcel);
                }
                //占用的行
                int occupyRow = relevantOrdersDetails.size();
                if (occupyRow != 1 && occupyRow != 0) {
                    int lastColIndex = firstColIndex + occupyRow - 1;
                    //需要合并的单元格，
                    //firstRow: 起始行号，0 表示工作表的第一行。
                    //lastRow: 结束行号，包括此行，应大于或等于 firstRow。
                    //firstCol: 起始列号，0 表示工作表的第一列。
                    //lastCol: 结束列号，包括此列，应大于或等于 firstCol。
                    cellRangeAddresses.add(new CellRangeAddress(firstColIndex, lastColIndex, 0, 0));
                    cellRangeAddresses.add(new CellRangeAddress(firstColIndex, lastColIndex, 1, 1));
                    cellRangeAddresses.add(new CellRangeAddress(firstColIndex, lastColIndex, 8, 8));
                    cellRangeAddresses.add(new CellRangeAddress(firstColIndex, lastColIndex, 9, 9));
                    cellRangeAddresses.add(new CellRangeAddress(firstColIndex, lastColIndex, 10, 10));
                    cellRangeAddresses.add(new CellRangeAddress(firstColIndex, lastColIndex, 11, 11));
                    cellRangeAddresses.add(new CellRangeAddress(firstColIndex, lastColIndex, 12, 12));
                    cellRangeAddresses.add(new CellRangeAddress(firstColIndex, lastColIndex, 13, 13));
                    cellRangeAddresses.add(new CellRangeAddress(firstColIndex, lastColIndex, 14, 14));
                    cellRangeAddresses.add(new CellRangeAddress(firstColIndex, lastColIndex, 15, 15));
                    cellRangeAddresses.add(new CellRangeAddress(firstColIndex, lastColIndex, 16, 16));
                    cellRangeAddresses.add(new CellRangeAddress(firstColIndex, lastColIndex, 17, 17));
                    cellRangeAddresses.add(new CellRangeAddress(firstColIndex, lastColIndex, 18, 18));
                    cellRangeAddresses.add(new CellRangeAddress(firstColIndex, lastColIndex, 19, 19));
                }
                firstColIndex += occupyRow;
            }
            //有图片的列
            List<Integer> imageIndex = Arrays.asList(9,10,14);
            CustomImageModifyHandler customImageModifyHandler = new CustomImageModifyHandler(0, Arrays.asList(1, 3), cellRangeAddresses,imageIndex);

            // 定义批次大小
            int batchSize = 50;
            // 获取数据总数
            int totalCount = list.size();
            // 计算需要分批的次数
            int batchCount = (totalCount + batchSize - 1) / batchSize;
            outputStream = new FileOutputStream(orderPath + splitName + ".xlsx");
            // 循环分批写入数据
            ExcelWriter excelWriter = EasyExcel.write(outputStream, ReimbursementOrdersExcel.class).excelType(ExcelTypeEnum.XLSX).registerWriteHandler(customImageModifyHandler).build();
            // 这里注意 如果同一个sheet只要创建一次
            WriteSheet writeSheet = EasyExcel.writerSheet("Sheet1").build();
            for (int i = 0; i < batchCount; i++) {
                int startIndex = i * batchSize;
                int endIndex = Math.min(startIndex + batchSize, totalCount);
                List<ReimbursementOrdersExcel> batchData = list.subList(startIndex, endIndex);
                excelWriter.write(batchData, writeSheet);
            }
            log.info(String.format("===已写入拆分文件%s===",splitName));
            // 关闭流
            excelWriter.finish();
            return 1;
        } catch (Exception e) {
            log.error("===导出报销单出错===", e);
            return 0;
        }finally {
            if (outputStream != null) {
                try {
                    outputStream.flush();
                    outputStream.close();
                } catch (IOException e) {
                    log.error("===关闭IO流出错===", e);
                }
            }
        }
    }

    @Override
    public void downloadExcel(HttpServletResponse response, Integer id) {
        Admin admin = memberService.getAdmin();
        if (admin.getId() == null) {
            throw new ApiException("你无权限下载！");
        }
        ReimbursementExcelRecord reimbursementExcelRecord = reimbursementExcelRecordMapper.selectByPrimaryKey(id);
        Integer fileSplitQuantity = reimbursementExcelRecord.getFileSplitQuantity();
        //文件名，不带后缀
        String fileName = reimbursementExcelRecord.getFileName().split("\\.")[0];
        if(fileSplitQuantity < 1){
            throw new ApiException("当前下载的文件不存在");
        }
        if (fileSplitQuantity == 1) {//不需要打成压缩包
            //文件在服务器的路径
            String serverPath = orderPath + fileName + "(1).xlsx";
            InputStream inputStream = null;
            OutputStream out = null;
            //根据文件在服务器的路径读取该文件转化为流
            File file = new File(serverPath);
            if (file.exists()) {
                try {
                    inputStream = new FileInputStream(file);
                    //创建一个Buffer字符串
                    byte[] buffer = new byte[1024];
                    response.setContentType("application/octet-stream;charset=ISO8859-1");
                    response.setHeader("Content-Disposition", "attachment;filename=" + reimbursementExcelRecord.getFileName());
                    response.addHeader("Pargam", "no-cache");
                    response.addHeader("Cache-Control", "no-cache");
                    out = response.getOutputStream();
                    int b = 0;
                    while (b != -1) {
                        b = inputStream.read(buffer);
                        //写到输出流(out)中
                        out.write(buffer, 0, b);
                    }
                } catch (Exception e) {
                    log.error("下载报销单出错！", e);
                    throw new ApiException("下载报销单出错!");
                } finally {
                    try {
                        if (inputStream != null) {
                            inputStream.close();
                        }
                        if (out != null) {
                            out.close();
                            out.flush();
                        }
                    } catch (Exception e) {
                        log.error("下载报销单关闭流出错！", e);
                        throw new ApiException("下载报销单关闭流出错!");
                    }
                }
            } else {
                throw new ApiException("当前下载的文件不存在，或者已被清理!");
            }
        } else {//需要打成压缩包
            ZipOutputStream zos = null;
            OutputStream out = null;
            try {
                // 将压缩包返回给客户端
                response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
                response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".zip");
                response.getOutputStream();
                out = response.getOutputStream();
                zos = new ZipOutputStream(out);
                for (Integer i = 0; i < fileSplitQuantity; i++) {
                    String splitFileName = fileName + "(" + (i + 1) + ")";
                    String serverPath = orderPath + splitFileName + ".xlsx";
                    File file = new File(serverPath);
                    if (file.exists()) {
                        // 创建ZipEntry对象，并添加到压缩包中
                        ZipEntry entry = new ZipEntry(file.getName());
                        zos.putNextEntry(entry);
                        // 创建FileInputStream对象，读取Excel文件内容，并写入压缩包中
                        FileInputStream fis = new FileInputStream(file);
                        byte[] buffer = new byte[1024];
                        int len;
                        while ((len = fis.read(buffer)) > 0) {
                            zos.write(buffer, 0, len);
                        }
                        fis.close();
                    } else {
                        throw new ApiException("当前下载的文件不存在，或者已被清理!");
                    }
                }
            } catch (IOException e) {
                log.error("下载报销单出错:", e);
                throw new ApiException("下载报销单出错");
            } finally {
                try {
                    if (zos != null) {
                        zos.close();
                    }
                    if(out != null){
                        out.close();
                        out.flush();
                    }
                } catch (Exception e) {
                    log.error("下载报销单文件关闭流出错! ",e);
                    throw new ApiException("下载报销单文件关闭流出错");
                }
            }
        }
    }

    @Override
    public List<Banker> getBankerByName(String bankerName) {
        String key = "banker:allBanker";
        String s = redisService.get(key);
        if(StringUtils.isNotEmpty(s)){
            List<Banker> bankers = JSONObject.parseArray(s, Banker.class);
            if(StringUtils.isNotEmpty(bankerName)){
                List<Banker> filterBanker = bankers.stream().filter(e -> e.getName().contains(bankerName)).collect(Collectors.toList());
                return filterBanker;
            }
            return bankers;
        } else {
            Map map = new HashMap<>();
            map.put("bankerName", bankerName);
            String result = HttpClientUtil.doGet(supplyApiConfig.getUrl() + "/banker/getBankerInfoByName", map, supplyApiConfig.getHeadsMap());
            CommonResult commonResult = JSONObject.parseObject(result, CommonResult.class);
            List<Banker> bankers = JSON.parseArray(JSON.toJSONString(commonResult.getData()), Banker.class);
            if(StringUtils.isEmpty(bankerName)){
                redisService.set(key,JSON.toJSONString(bankers),60);
            }
            return bankers;
        }
    }

    @Override
    public CommonPage<ReimbursementExportRecordResponse> getExportRecord(Integer pageNum, Integer pageSize, String adminName) {
        PageHelper.startPage(pageNum,pageSize);
        List<ReimbursementExportRecordResponse> excelRecordHistory = reimbursementOrdersDao.getExcelRecordHistory();
        return CommonPage.restPage(excelRecordHistory);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String delReimbursementOrders(List<Integer> ids) {
        Admin admin = memberService.getAdmin();
        List<Menu> menuAllByTel = adminService.getMenuAllByTel(admin.getEmail());
        boolean isPermission = menuAllByTel.stream().anyMatch(e -> "reimbursement:delete".equals(e.getApiCode()));
        StringBuffer errorMsg = new StringBuffer();
        for (Integer id : ids) {
            String key = RedisConstants.REIMBURSEMENT_AUDIT_KEY+id;
            String adminId = redisService.get(key);
            //1.审核
            if (StringUtils.isNotBlank(adminId)) {
                if (!adminId.equals(admin.getId().toString())) {
                    Admin optAdmin = adminMapper.selectByPrimaryKey(Integer.valueOf(adminId));
                    throw new ApiException("当前报销单" + optAdmin.getName() + "正在审批中，无法删除！");
                }
            }
            RLock lock = redissonClient.getLock(RedisConstants.REIMBURSEMENT_LOCK_ + id);
            ReimbursementOrders reimbursementOrders = reimbursementOrdersMapper.selectByPrimaryKey(id);
            try {
                boolean b = lock.tryLock(0, 5, TimeUnit.SECONDS);
                if(b){
                    if (!isPermission && !reimbursementOrders.getCreateUserId().equals(admin.getId())) {
                        errorMsg.append(String.format("无权限删除他人创建的报销单:%s,请联系管理人员操作！", reimbursementOrders.getReimbursementNo()));
                        continue;
                    }
                    if (null != reimbursementOrders.getReimbursementTime()) {
                        errorMsg.append(String.format("删除失败，无法删除已报销的报销单：%s; ", reimbursementOrders.getReimbursementNo()));
                        continue;
                    }
                    reimbursementOrdersDao.delReimbursementOrders(id);
                    reimbursementOrdersDao.delReimbursementOrdersDetails(id);
                }
            } catch (Exception e) {
                errorMsg.append(String.format("删除报销单：%s 出错; ", reimbursementOrders.getReimbursementNo()));
            } finally {
                lock.unlock();
            }
        }
        return errorMsg.toString();
    }

    @Override
    public List<ReiOrderResponse> getReimbursementHistory(String childOrderNo) {
        List<ReimbursementOrdersInfo> childOrderNoAssociated = reimbursementOrdersDao.getChildOrderNoAssociated(childOrderNo);
        List<Integer> reimbursementId = childOrderNoAssociated.stream().map(ReimbursementOrdersInfo::getReimbursementId).collect(Collectors.toList());
        List<ReiOrderResponse> responses = new ArrayList<>();
        for (Integer id : reimbursementId) {
            ReiOrderResponse reiOrderDetail = getReiOrderDetail(id);
            responses.add(reiOrderDetail);
        }
        List<ReiOrderResponse> collect = responses.stream().sorted(Comparator.comparing(ReiOrderResponse::getId).reversed()).collect(Collectors.toList());
        return collect;
    }

    @Override
    public Integer analysisReimbursementExcel() {
        ExcelRead excelRead = new ExcelRead();
        List<ExcelData> list = excelRead.list();
        System.out.println(list.size());
        return null;
    }

    @Override
    public String markAuditStatus(Integer id, Integer mark) {
        Admin admin = memberService.getAdmin();
        String key = RedisConstants.REIMBURSEMENT_AUDIT_KEY+id;
        String adminId = redisService.get(key);
        //1.审核
        if(mark == 1){
            if(StringUtils.isNotBlank(adminId)){
                if(!adminId.equals(admin.getId().toString())){
                    Admin optAdmin = adminMapper.selectByPrimaryKey(Integer.valueOf(adminId));
                    return "当前报销单"+optAdmin.getName()+"正在审批中，无法操作！";
                }
            }else {
                redisService.set(RedisConstants.REIMBURSEMENT_AUDIT_KEY+id,admin.getId().toString(),2*60*60);
            }
        } else if(mark == 0){//取消
            if(StringUtils.isNotBlank(adminId)){
                if(!adminId.equals(admin.getId().toString())){
                    Admin optAdmin = adminMapper.selectByPrimaryKey(Integer.valueOf(adminId));
                    return "无法取消"+optAdmin.getName()+"正在审批中的报销单！";
                }
            }
            redisService.remove(key);
        } else if(mark == 2){//确认
            if(StringUtils.isNotBlank(adminId)){
                if(!adminId.equals(admin.getId().toString())){
                    Admin optAdmin = adminMapper.selectByPrimaryKey(Integer.valueOf(adminId));
                    return "无法操作"+optAdmin.getName()+"正在审批中的报销单！";
                }
            }
            redisService.remove(key);
        }
        return "";
    }

    public static void main(String[] args) {
        DateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        String fileName = "报账订单" + sdf.format(new Date());
        System.out.println(fileName);
    }
}
